import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Rebates } from './assets/rebates.entity';
import { Repository } from 'typeorm';
import {
  Rebastes_RebastesStatic_Dto,
  RebatesWeb_Find_Dto,
  Rebates_OrderListFind_Dto,
} from './assets/rebates.dto';
import {
  Constant_Enum_Enum_Order_PayStatus,
  Constant_Enum_Enum_Rebates_DistributionStatus,
  Constant_Enum_Enum_Rebates_RebatesType,
  Constant_Enum_Enum_Scheduled_Type,
} from '@/common/constants/enum';
import { util_Db_PageList } from '@/common/util/db';
import { IRequest } from '@/common/typeScripts';
import { Cron, Timeout } from '@nestjs/schedule';

@Injectable()
export class Rebates_Service {
  constructor(
    @InjectRepository(Rebates)
    private rebates_Repository: Repository<Rebates>,
  ) {}
  async rebastes_RebastesStatic(query: Rebastes_RebastesStatic_Dto) {
    const subQb = this.rebates_Repository
      .createQueryBuilder('rebates')
      .select('SUM(rebates.rebatesMoney)', 'secondDistributionMoney')
      .addSelect('COUNT(rebates.id)', 'secondCount')
      .where('rebates.rebatesType = :rebatesType', {
        rebatesType: Constant_Enum_Enum_Rebates_RebatesType.Rebates_RebatesType_SecondedOrder,
      });
    const subQbed = this.rebates_Repository
      .createQueryBuilder('rebates')
      .select('SUM(rebates.rebatesMoney)', 'firstDistributionMoney')
      .addSelect('COUNT(rebates.id)', 'firstCount')
      .where('rebates.rebatesType = :rebatesType', {
        rebatesType: Constant_Enum_Enum_Rebates_RebatesType.Rebates_RebatesType_FirstOrder,
      });
    if (query.startTime) {
      subQb.andWhere('rebates.createTime >= :startTime', { startTime: query.startTime });
      subQbed.andWhere('rebates.createTime >= :startTime', { startTime: query.startTime });
    }
    if (query.endTime) {
      subQb.andWhere('rebates.createTime <= :endTime', { endTime: query.endTime });
      subQbed.andWhere('rebates.createTime <= :endTime', { endTime: query.endTime });
    }
    let retuobj: {
      secondDistributionMoney: number;
      secondCount: number;
      firstDistributionMoney: number;
      firstCount: number;
    } = { secondDistributionMoney: 0, secondCount: 0, firstDistributionMoney: 0, firstCount: 0 };
    const secondData = await subQb.getRawOne();
    const firstData = await subQbed.getRawOne();
    retuobj = { ...retuobj, ...secondData, ...firstData };
    return retuobj;
  }

  async rebastes_OrderListFindByPage(query: Rebates_OrderListFind_Dto) {
    return await util_Db_PageList<Rebates>({
      queryBuilder: this.rebates_Repository
        .createQueryBuilder('rebates')
        .leftJoin('rebates.order', 'order')
        .leftJoin('rebates.invitee', 'invitee')
        .leftJoin('order.orderVirtualDetail', 'orderVirtualDetail')
        .leftJoin('orderVirtualDetail.good', 'good')
        .leftJoin('good.product', 'product')
        .leftJoin('product.platform', 'platform')
        .select([
          'invitee.id AS userClientId',
          'invitee.userName AS userClientName',
          'platform.platFormName AS platFormName',
          'product.productName AS productName',
          'order.createTime AS orderCreateTime',
          'order.status AS orderStatus',
          'order.payPrice AS orderPayPrice',
          'rebates.rebatesMoney AS rebatesMoney',
          'rebates.rebatesStatus AS rebatesStatus',
          'rebates.rebatesType AS rebatesType',
          'rebates.rebatesTime AS rebatesTime',
        ]),
      query: {
        page: query.page,
        size: query.size,
      },
      isRaw: true,
    });
  }

  async rebatesWeb_UserClientDetail_Util(req: IRequest, rebatesStatus: any) {
    const result = await this.rebates_Repository
      .createQueryBuilder('rebates')
      .leftJoin('rebates.inviter', 'inviter')
      .select('SUM(rebates.rebatesMoney)', rebatesStatus + 'Money')
      .where('rebates.rebatesStatus= :rebatesStatus', {
        rebatesStatus: rebatesStatus,
      })
      .where('inviter.id= :inviter', {
        inviter: req.user.userId,
      })
      .getRawOne();
    if (result[rebatesStatus + 'Money'] == null) return { [rebatesStatus + 'Money']: 0 };
    return result;
  }

  async rebatesWeb_UserClientDetail(req: IRequest) {
    const promiseList = [];
    Object.values(Constant_Enum_Enum_Rebates_DistributionStatus).forEach((rebateType) => {
      console.log(rebateType);
      promiseList.push(async () => await this.rebatesWeb_UserClientDetail_Util(req, rebateType));
    });
    const results = await Promise.all([
      promiseList[0](),
      promiseList[1](),
      promiseList[2](),
      promiseList[3](),
    ]);
    return { ...results[0], ...results[1], ...results[2], ...results[3] };
  }

  async rebatesWeb_OrderDetail_Util(req: IRequest, rebatesStatus: any) {
    const result = await this.rebates_Repository
      .createQueryBuilder('rebates')
      .leftJoin('rebates.inviter', 'inviter')
      .select('COUNT(rebates.id)', 'count')
      .where('rebates.rebatesStatus= :rebatesStatus', {
        rebatesStatus: rebatesStatus,
      })
      .where('inviter.id= :inviter', {
        inviter: req.user.userId,
      })
      .getRawOne();
    if (result[rebatesStatus + 'Count'] == null) return { [rebatesStatus + 'Count']: 0 };
    return result;
  }

  async rebatesWeb_OrderDetail(req: IRequest) {
    const promiseList = [];
    Object.values(Constant_Enum_Enum_Rebates_DistributionStatus).forEach((rebateType) => {
      promiseList.push(() => this.rebatesWeb_OrderDetail_Util(req, rebateType));
    });
    const results = await Promise.all([
      promiseList[0](),
      promiseList[1](),
      promiseList[2](),
      promiseList[3](),
    ]);
    const refundOrderNum = await this.rebates_Repository
      .createQueryBuilder('rebates')
      .leftJoin('rebates.order', 'order')
      .leftJoin('rebates.inviter', 'inviter')
      .select('COUNT(rebates.id)', 'count')
      .where('order.status= :status', {
        status: Constant_Enum_Enum_Order_PayStatus.order_PayStatus_Refund,
      })
      .where('inviter.id= :inviter', {
        inviter: req.user.userId,
      })
      .getRawOne();
    return {
      refundOrderNum: refundOrderNum.count,
      ...results[0],
      ...results[1],
      ...results[2],
      ...results[3],
    };
  }

  async rebatesWeb_OrderList(req: IRequest, query: RebatesWeb_Find_Dto) {
    return await util_Db_PageList({
      queryBuilder: this.rebates_Repository
        .createQueryBuilder('rebates')
        .leftJoin('rebates.inviter', 'inviter')
        .leftJoin('rebates.order', 'order')
        .leftJoin('order.orderVirtualDetail', 'orderVirtualDetail')
        .leftJoin('orderVirtualDetail.good', 'good')
        .leftJoin('good.product', 'product')
        .leftJoin('product.platform', 'platform')
        .select([
          'inviter.userName AS userName',
          'order.status AS status',
          'product.productName AS productName',
          'platform.platFormName AS platFormName',
          'rebates.createTime AS createTime',
          'rebates.rebatesStatus AS rebatesStatus',
          'rebates.rebatesMoney AS rebatesMoney',
        ])
        .where('inviter.id= :inviter', {
          inviter: req.user.userId,
        }),
      query: { page: query.page, size: query.size },
      isRaw: true,
    });
  }

  @Timeout(Constant_Enum_Enum_Scheduled_Type.Scheduled_Type_RebaseStatus, 100000)
  async rebatesWeb_StartCancelOrderSchedule() {
    const rebates = await this.rebates_Repository
      .createQueryBuilder('rebates')
      .where('rebates.rebatesStatus= :rebatesStatus', {
        rebatesStatus:
          Constant_Enum_Enum_Rebates_DistributionStatus.InviteRelation_DistributionStatus_OutGoing,
      })
      .andWhere('rebates.createTime < :createTime', {
        createTime: new Date().getTime() + 3600 * 1000 * 24 * 7,
      })
      .getMany();
    rebates.forEach((item) => {
      item.rebatesStatus =
        Constant_Enum_Enum_Rebates_DistributionStatus.InviteRelation_DistributionStatus_OutGoed;
    });
    this.rebates_Repository.save(rebates);
  }

  @Cron('0 0 5 * * *')
  async seat_InvalidHandle() {
    this.rebatesWeb_StartCancelOrderSchedule();
  }
}
